#include "txtsplit.h"


void substr(const char *str,int strlen);
void saveToFile(const char *fileNamePre , int fileIndex , const char *fileContent , long fileContentLen);
void printfParam(int argc,char **argv);
void initAppParam(int argc,char **argv);
void mallocFor_BF_fileContent(long needSize);
void printfAppHelp();

long FDPOS_now = 0;//文件当前的读写位置;
long FDPOS_lastseek = 0;//上一次进行有效操作的读写位置
long OPENFILEPATH_SIZE = 0;//文件大小

int BFS_copyBufferSize = 1024;//当前缓冲区大小
char *BF_copyBuffer;//内容拷贝缓冲区

int BFS_fileContentSize = 100;//每次读入文件内容的缓冲区大小,这个大小是在使用过程中会变化的
char *BF_fileContent;//文件内容缓冲区

char *OPENFILEPATH = NULL;//打开的文件
char *SAVE_FILE_DIR = NULL;//文件保存的目录
char *SAVE_FILE_PRENAME = NULL;//保存文件的文件名前缀
char *FILE_SPLITER = NULL;//文件内容分割（字）符（串)
int FILE_SPLITER_SIZE = 255;//文件内容分割（字）符（串)的最大长度
int FILENUM_INDIR = 200;//每多少个文件一个目录

char *APPENV_LocalEncode = NULL;//本地环境字符编码
char *APPENV_OpenFileEncode = NULL;//打开的文件字符编码


struct timeval runStartTime,runEndTime;


int main(int argc,char **argv)
{
    char *GETENV_LANG = getenv("LANG");
    char *tmpstr;
    APPENV_LocalEncode = strtok(GETENV_LANG,".");
    while(( tmpstr = strtok(NULL,".")) != NULL)
    {
       APPENV_LocalEncode = tmpstr;
    }
    APPENV_OpenFileEncode = APPENV_LocalEncode;
    printf("本地编码:%s\r\n",APPENV_LocalEncode);
    initAppParam(argc,argv);
//    exit(0);

    gettimeofday(&runStartTime,NULL);
    char *fengexian = "===================================================\r\n";
    long thestrlen = 0;//本次读入内容时，发现的长度
    long substrlen =0;//需要截取的从长度


    int fd = open(OPENFILEPATH,O_RDONLY);
    //lseek(fd,50,SEEK_SET);
    if(fd >0)
    {
        struct stat filestat;
        fstat(fd ,&filestat);
        OPENFILEPATH_SIZE = (long)filestat.st_size;
        printf("打开文件成功,文件大小:%ld\r\n",OPENFILEPATH_SIZE);
    }else
    {
        printf("文件:%s 不存在\r\n",OPENFILEPATH);
        exit(0);
    }



    BF_copyBuffer = malloc(BFS_copyBufferSize+1);//先初始化一次这个玩意的大小
    BF_fileContent = calloc(BFS_fileContentSize+1,sizeof(char));

    int RS_read,readNum = 0;
    char *CP_findpos;//找到分隔符时候的指针

    while(FDPOS_lastseek < OPENFILEPATH_SIZE )
    {
        lseek(fd,FDPOS_now,SEEK_SET);//移动到下一个位置

        mallocFor_BF_fileContent(BFS_fileContentSize);
        RS_read = read(fd,BF_fileContent,BFS_fileContentSize);


//        int p;
//        printf("========FILE_SPLITER============\r\n");
//        size_t len = strlen(FILE_SPLITER);
//        for(p=0;p<len;p++)
//        {
//            printf("%x ",FILE_SPLITER[p]);
//        }
//        printf("\r\n");
//        exit(0);

//        printf("get content:%s\r\n" , BF_fileContent);

        CP_findpos = strstr(BF_fileContent,FILE_SPLITER);
        if(CP_findpos == NULL)
        {
//            printf("找不到啦\r\n");
            FDPOS_now += BFS_fileContentSize;//继续偏移
            if(FDPOS_now < OPENFILEPATH_SIZE)
            {
                continue;
            }else
            {
                //没有内容了,那就存文件咯
//                printf("没内容了\r\n");
                thestrlen = -1;
                substrlen = OPENFILEPATH_SIZE - FDPOS_lastseek;
            }
        }else
        {
            //找到分割文本了
//            printf("找到啦:%s\r\n",CP_findpos);
            thestrlen = CP_findpos - BF_fileContent;
            substrlen = FDPOS_now - FDPOS_lastseek + thestrlen;
        }


        //检查读入缓冲区大小是否足够大，不够就重新分配内存
        mallocFor_BF_fileContent(substrlen);

        if(substrlen != thestrlen)
        {
            //两次内容不一致，需要重新读入文件内容
            lseek(fd,FDPOS_lastseek,SEEK_SET);

            RS_read = read(fd,BF_fileContent,substrlen);
            if(RS_read <0)
            {
                printf("读取文件失败在位置:%ld,从长度,%ld\r\n",FDPOS_lastseek,OPENFILEPATH_SIZE);
                break;
            }

            substr(BF_fileContent,substrlen);
        }else
        {
            //拷贝内容
            substr(BF_fileContent,substrlen);
        }


//        printf("文件偏移(%ld),长度:(%ld):%s\r\n" , FDPOS_lastseek , substrlen , BF_copyBuffer);

        saveToFile(SAVE_FILE_PRENAME,readNum,BF_copyBuffer,substrlen);


        FDPOS_lastseek += substrlen;//这里需要再移动1
        FDPOS_now = FDPOS_lastseek+1;

//        break;
        readNum++;
//        if(readNum>2)
//        {
//            break;
//        }
    }//end while(1)

    printf("%s",fengexian);
    free(BF_fileContent);
    free(BF_copyBuffer);
    close(fd);

    gettimeofday(&runEndTime,NULL);

    int useSecond = runEndTime.tv_sec-runStartTime.tv_sec;
    int useMicroSecond = runEndTime.tv_usec - runStartTime.tv_usec;

    if(useMicroSecond <0)
    {
        useSecond --;
        useMicroSecond += 1000000;
    }

    printf("happy work,useTime:%d.%d\r\n",useSecond,useMicroSecond);
    return 0;
}

/**
  打印参数，调试用的

  **/
void printfParam(int argc,char **argv)
{
    int p;
    while((p=getopt(argc,argv,"f:s:p:e")) >=0)
    {
        switch(p)
        {
            default:
            printf("get param %c=>%s:\r\n",p,optarg);
            break;
        }
    }

}

void initAppParam(int argc,char **argv)
{
    if(argc < 2)
    {
        //什么参数都没传递
        printfAppHelp();
    }

    if(argc %2 == 0)
    {
        printf("Invalid Argument Count\r\n");
        exit(1);
    }

    int p;
    while((p=getopt(argc,argv,"f:d:p:s:e:")) >=0)
    {
        switch(p)
        {
            case 'f'://打开的文件
            OPENFILEPATH = optarg;
            break;

            case 'd'://保存的目录
            SAVE_FILE_DIR = optarg;
            break;

            case 'p'://文件名前缀
            SAVE_FILE_PRENAME = optarg;
            break;

            case 's'://分割字符串
            FILE_SPLITER = optarg;
            printf("获得分隔符(%d):%s\r\n" , (int)strlen(FILE_SPLITER) , FILE_SPLITER);
            break;

            case 'S'://多少个文件一个目录
            FILENUM_INDIR = atoi(optarg);
            break;

            case 'e'://文件编码
            APPENV_OpenFileEncode = optarg;
            break;

            default:
            printf("unknow param %c:\r\n",p);
            break;
        }
    }




    if(OPENFILEPATH == NULL)
    {
        printf("Param f lose\r\n");
        exit(3);
    }

    if(SAVE_FILE_DIR == NULL)
    {
        printf("Param d lose\r\n");
        exit(3);
    }

    if(FILE_SPLITER == NULL)
    {
        printf("Param s lose\r\n");
        exit(3);
    }

    if(FILENUM_INDIR < 10)
    {
        FILENUM_INDIR = 200;
    }

    if(SAVE_FILE_PRENAME == NULL)
    {
        SAVE_FILE_PRENAME = "";
    }

    size_t tmp_spliter_size = 20;
//    char tmp_spliter[tmp_spliter_size];
    char *tmp_p_buff = calloc(tmp_spliter_size+1,sizeof(char));
    char *p_tmp_spliter = tmp_p_buff;
//    memset(tmp_p_buff,0,tmp_spliter_size+1);

    size_t FILE_SPLITER_strlen = strlen(FILE_SPLITER);
    size_t iconvrs;

    if(strcasecmp(APPENV_OpenFileEncode , APPENV_LocalEncode) != 0)
    {
        //文件编码跟本地编码不一样
        char *FILE_SPLITER_copy = FILE_SPLITER;
        printf("before(%d):%s\r\n",(int)FILE_SPLITER_strlen,FILE_SPLITER_copy);
        iconv_t ict = iconv_open(APPENV_OpenFileEncode,APPENV_LocalEncode);
        errno = 0;
        iconvrs = iconv(ict,&FILE_SPLITER_copy,&FILE_SPLITER_strlen,&p_tmp_spliter,&tmp_spliter_size);
        iconv_close(ict);
//        printf("test(errno:%d)[%d]:%s|%s\r\n",(int)iconvrs,(int)strlen(tmp_p_buff),tmp_p_buff,FILE_SPLITER);

        if(iconvrs == -1)
        {
            printf("iconv error,from:%d,error:%s\r\n" , (int)strlen(FILE_SPLITER), strerror(errno));
            exit(0);
        }
//        printf("encode(rs:%d)(errno:%d):strlen:%d(iconvoutlen:%d):%s\r\n",(int)iconvrs,errno, (int)strlen(tmp_p_buff) ,(int)tmp_spliter_size, tmp_p_buff);

        FILE_SPLITER = tmp_p_buff;
        printf("final FILE_SPLITER(%d):%s\r\n",(int)strlen(FILE_SPLITER),FILE_SPLITER);
        for(p=0;p<strlen(FILE_SPLITER);p++)
        {
            printf("%x ",FILE_SPLITER[p]);
        }
        printf("\r\n");
    //    exit(0);
    }

}


/**
  重新调整文件缓冲区大小
  如果已有缓冲区比需要调整的还大，只作清空处理
  **/
void mallocFor_BF_fileContent(long needSize)
{
    if(needSize> BFS_fileContentSize )
    {
        free(BF_fileContent);
        BFS_fileContentSize = needSize;
        BF_fileContent = malloc(BFS_fileContentSize*sizeof(char)+1);
    }
    memset(BF_fileContent,0,BFS_fileContentSize);
}

/**
  打印工具帮助
  **/
void printfAppHelp()
{
    printf("TxtSpliter Version:%s\r\n",APP_VERSION);
    printf("指定字符串作为分隔符，把一个大文件分割成多个小文件,just try it\r\n");
    printf("必须提供的参数\r\n");
    printf("\t-f :   指定要分割的文件\r\n");
    printf("\t-d :   指定分割后的文件保存的目录，目录不存在会自动创建\r\n");
    printf("\t-s :   指定分割分割文件的字符串\r\n");
    printf("可选的参数\r\n");
    printf("\t-S :   每多少个文件一个目录，默认是200\r\n");
    printf("\t-p :   指定分割后的文件名前缀\r\n");
    printf("\t-e :   指定文件编码,默认是跟当前系统编码一致\r\n");
    exit(0);
}



/**
    截取字符串
    */
void substr(const char *str,int strlen)
{
    if(strlen > BFS_copyBufferSize)
    {
        BFS_copyBufferSize = strlen;
        free(BF_copyBuffer);
        BF_copyBuffer = malloc(BFS_copyBufferSize+1);
    }
    memset(BF_copyBuffer,0,BFS_copyBufferSize);
    strncpy(BF_copyBuffer,str,strlen);
    BF_copyBuffer[BFS_copyBufferSize] = 0;
}

/**
  保存到文件
  */
void saveToFile(const char *fileNamePre , int fileIndex , const char *fileContent , long fileContentLen)
{

    errno = 0;
    DIR *dirstat = opendir(SAVE_FILE_DIR);

    int RS_mkdir =0;

//    printf("opendir %d\r\n",dirstat == NULL);

    if(dirstat == NULL)
    {
        RS_mkdir = mkdir(SAVE_FILE_DIR,0777);
        if(RS_mkdir == -1)
        {
            printf("create dir fail,1:%s,error:%s\r\n" , SAVE_FILE_DIR,strerror(errno));
            return ;
        }
    }
    closedir(dirstat);

    char *saveDir = calloc(1024,sizeof(char));
    errno = 0;
    sprintf(saveDir,"%s/%d/",SAVE_FILE_DIR , fileIndex/FILENUM_INDIR);

    dirstat = opendir(saveDir);
    if(dirstat == NULL)
    {
        RS_mkdir = mkdir(saveDir,0777);
        if(RS_mkdir == -1)
        {
            printf("create dir fail,2:%s,error:%s\r\n" , SAVE_FILE_DIR,strerror(errno));
            free(saveDir);
            return ;
        }
    }
    closedir(dirstat);

    char *saveFilePath = calloc(1024,sizeof(char));


    sprintf(saveFilePath,"%s/%s%d.txt",saveDir ,fileNamePre,fileIndex);

    errno = 0;
    unlink(saveFilePath);
    int sfd = open(saveFilePath,O_CREAT|O_RDWR,S_IRGRP|S_IWGRP|O_RDWR|S_IWUSR|S_IRUSR);
    if(sfd <0)
    {
        free(saveFilePath);
        free(saveDir);
        printf("saveFile Fail:%s , error:%s\r\n",saveFilePath,strerror(errno));
        return;
    }

    errno = 0;
    int RS_write = write(sfd , fileContent, fileContentLen);
    if(RS_write <0)
    {
        printf("save file Error:(%d)(%s):%s\r\n" , RS_write , strerror(errno) , saveFilePath);
    }

    printf("save:%s\r\n",saveFilePath);

    free(saveFilePath);
    free(saveDir);

    close(sfd);
}

